//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================
#include "memspy.h"
#include "usyscall.h"
#include <elacs.h>

#if defined(MEMORYSPY)

#define PAGE_SIZE               0x1000
#define PAGE_SHIFT              12

static PMEMSPYNODE g_processHashList[HASH_SIZE_OF_PROCESS];
static PMEMSPYTHREAD g_threadHashList[HASH_SIZE_OF_THREAD];
static UInt32 g_uCurrentAllocedTimesOfProcess;
static UInt32 g_uStopIndex = 0;
static _ELASTOS Boolean g_bPrintMore = FALSE;

CriticalSection g_sectMemSpy;
static UInt32 g_uOverrunAddress = 0x0;
//////////////////////////////////////////////////////////////////////////////

void *TaskMemAlloc(UInt32 size, _ELASTOS Boolean zeroMem);
void TaskMemFree(void *pMem);
void *TaskMemRealloc(void *pMem, UInt32 size);

//// The following MemSpy functions to be used to replace '_CMemoryHeap_Alloc',
//// '_CMemoryHeap_Free', '_CMemoryHeap_Realloc' and so on defined in
//// taskmem.cpp.

ELAPI_(PVoid) _CMemoryHeap_Alloc(MemorySize size, Boolean zeroMem)
{

    UInt32 ulExpandedSize = MSpyExpandRequestSize(size);
    if ((UInt32)-1 == ulExpandedSize)
        return NULL;

    PVoid pExpandedHeapBlock, pRequestHeapBlock;

    pExpandedHeapBlock = TaskMemAlloc(ulExpandedSize, zeroMem);

    if (NULL == pExpandedHeapBlock) return NULL;

    pRequestHeapBlock = MSpyRetrieveRequestHeapBlock(pExpandedHeapBlock);

    Void * pContext = _Elastos_CriticalSection_Enter(&g_sectMemSpy);

#if 0 // _x86
    *(int *)((byte_t *)pRequestHeapBlock + size) = MEMSPYOVERRUNCHECKSUM;
#else // _x86
    UInt32 uMSpyCheckSum = MEMSPYOVERRUNCHECKSUM;
    memcpy((byte_t *)pRequestHeapBlock + size, &uMSpyCheckSum, sizeof(UInt32));
#endif // _x86

    MSpyAddMemSpyNodeInfoToProcessHash(pRequestHeapBlock, (UInt32)size);

    _Elastos_CriticalSection_Leave(&g_sectMemSpy, pContext);

    if (g_uStopIndex && g_uCurrentAllocedTimesOfProcess == g_uStopIndex) {
        if (g_uOverrunAddress != 0x0) {
            ECode ec = SysSetBreakPoint(0, BreakPointType_ReadWrite, \
                            (void *)((byte_t *)g_uOverrunAddress + size), \
                            MEMSPYFOROVERRUN);
            if (FAILED(ec)) {
                printf("*ERROR* Failed to call SysSetBreakPoint \
                                (ec = %x)\n", ec);
                DebugBreak();
            }

            return pRequestHeapBlock;
        }

        printf("\n\n******************************************************\n");
        printf("\nStop at: index = 0x%x\n", g_uCurrentAllocedTimesOfProcess);
        printf("\nThe debugger gdb may offer what you want, start it up!\n");
        printf("\n******************************************************\n\n");

        DebugBreak();
    }

    return pRequestHeapBlock;
}

ELAPI_(void) _CMemoryHeap_Free(PVoid pMem)
{
    if (NULL == pMem) {
#ifdef _DEBUG
        //printf("\nWARNING: You try to free a NULL pointer!\n");
#endif
        return;
    }

    if (IS_INVALID_HEAPBLOCK(pMem)) {
        printf("ERROR: Freeing an invalid memory block, "
               "or freeing a valid block twice will cause this error.\n");
        DebugBreak();
    }

    PMEMSPYNODE pMemSpyNode = NULL;

    Void * pContext = _Elastos_CriticalSection_Enter(&g_sectMemSpy);

    pMemSpyNode = MSpySearchMemSpyNodeFromProcessHash(pMem);

    if (NULL == pMemSpyNode) {
        printf("ERROR: free a non-spyed block. Freeing an invalid memory "
                "block, or freeing a valid block twice will cause \
                this error.\n");
        _Elastos_CriticalSection_Leave(&g_sectMemSpy, pContext);
        DebugBreak();
    }

    if (ISOVERRUN(pMem, pMemSpyNode->uRequestAllocedSize)) {
        printf("\n\nERROR: Heap block \"%d\" at 0x%08x overrun!\n\n",
            pMemSpyNode->uAllocIndexInProcess, pMem);
        _Elastos_CriticalSection_Leave(&g_sectMemSpy, pContext);
        DebugBreak();
    }

    MSpyDetachMemSpyNodeFromProcessHash(pMemSpyNode);

    _Elastos_CriticalSection_Leave(&g_sectMemSpy, pContext);

    PVoid pvExpandedHeapBlock = MSpyRetrieveExpandedHeapBlock(pMem);

    //Clear the magic number
    pMemSpyNode->uMagic = 0;

    TaskMemFree(pvExpandedHeapBlock);
}

ELAPI_(PVoid) _CMemoryHeap_Realloc(PVoid pMem, MemorySize size)
{
    if (pMem && IS_INVALID_HEAPBLOCK(pMem)) {
        printf("ERROR: Reallocating an invalid memory block.\n");
        DebugBreak();
    }

    UInt32 ulNewExpandedSize = size ? MSpyExpandRequestSize(size) :
        (pMem ? 0 : MSpyExpandRequestSize(size));
    if ((UInt32)-1 == ulNewExpandedSize) {
        return NULL;
    }

    PVoid pvOldExpandedHeapBlock;
    UInt32 ulOldExpandedSize;
    _ELASTOS Boolean bIsReallocSucceeded = TRUE;
    Void * pContext;

    if (pMem) {
       pContext = _Elastos_CriticalSection_Enter(&g_sectMemSpy);

        PMEMSPYNODE pOldMemSpyNode = MSpySearchMemSpyNodeFromProcessHash(pMem);
        if (NULL == pOldMemSpyNode) {
            printf("ERROR: realloc a non-spyed block. Freeing an \
                    invalid memory "
                    "block, or freeing a valid block twice will cause \
                    this error.\n");
            _Elastos_CriticalSection_Leave(&g_sectMemSpy, pContext);
            DebugBreak();
        }

        MSpyDetachMemSpyNodeFromProcessHash(pOldMemSpyNode);

        _Elastos_CriticalSection_Leave(&g_sectMemSpy, pContext);

        if (ISOVERRUN(pMem, pOldMemSpyNode->uRequestAllocedSize)) {
            printf("\n\nERROR: Heap block \"%d\" at 0x%08x overrun!\n\n",
                pOldMemSpyNode->uAllocIndexInProcess, pMem);
            DebugBreak();
        }

        UInt32 clearchksum = 0xcccccccc;
        PUInt32 puMem = (PUInt32)((byte_t *)pOldMemSpyNode->pvRequestAllocedBlock \
            + pOldMemSpyNode->uRequestAllocedSize);
        memcpy(puMem, (byte_t *)&clearchksum,  sizeof(UInt32));

        //Clear the magic number
        pOldMemSpyNode->uMagic = 0;

        pvOldExpandedHeapBlock = MSpyRetrieveExpandedHeapBlock(pMem);
        ulOldExpandedSize = MSpyExpandRequestSize(
                    pOldMemSpyNode->uRequestAllocedSize);
    }
    else {
        pvOldExpandedHeapBlock = NULL;
        ulOldExpandedSize = 0;
    }

    PVoid pNewExpandedHeapBlock = TaskMemRealloc(
                    pvOldExpandedHeapBlock, ulNewExpandedSize);

    if ((ulNewExpandedSize == 0) && (NULL != pvOldExpandedHeapBlock)) {
        // Free old block
        assert(pNewExpandedHeapBlock == NULL);
        return NULL;
    }

    // Not enough memory
    if (NULL == pNewExpandedHeapBlock) {
        if (NULL != pvOldExpandedHeapBlock) {
            pNewExpandedHeapBlock = pvOldExpandedHeapBlock;
            ulNewExpandedSize = ulOldExpandedSize;
            size = ((PMEMSPYNODE)pNewExpandedHeapBlock)->uRequestAllocedSize;
            bIsReallocSucceeded = FALSE;
        }
        else {
            return NULL;
        }
    }

    PVoid pRequestHeapBlock = MSpyRetrieveRequestHeapBlock(
                    pNewExpandedHeapBlock);

    pContext = _Elastos_CriticalSection_Enter(&g_sectMemSpy);

#if 0 // _x86
    *(int *)((byte_t *)pRequestHeapBlock + size) = MEMSPYOVERRUNCHECKSUM;
#else // _x86
    UInt32 uMSpyCheckSum = MEMSPYOVERRUNCHECKSUM;
    memcpy((byte_t *)pRequestHeapBlock + size, &uMSpyCheckSum, sizeof(UInt32));
#endif // _x86

    MSpyAddMemSpyNodeInfoToProcessHash(pRequestHeapBlock, (UInt32)size);

    _Elastos_CriticalSection_Leave(&g_sectMemSpy, pContext);

    if (g_uStopIndex && g_uCurrentAllocedTimesOfProcess == g_uStopIndex) {
        if (g_uOverrunAddress != 0x0) {
            ECode ec = SysSetBreakPoint(0, BreakPointType_ReadWrite, \
                            (void *)((byte_t *)g_uOverrunAddress + size), \
                            MEMSPYFOROVERRUN);
            if (FAILED(ec)) {
                printf("*ERROR* Failed to call SysSetBreakPoint \
                                (ec = %x)\n", ec);
                DebugBreak();
            }

            return pRequestHeapBlock;
        }

        printf("\n\n******************************************************\n");
        printf("\nStop at: index = 0x%x\n", g_uCurrentAllocedTimesOfProcess);
        printf("\nThe debugger gdb may offer what you want, start it up!\n");
        printf("\n******************************************************\n\n");

        DebugBreak();
    }

    return bIsReallocSucceeded ? pRequestHeapBlock : NULL;
}

//////////////////////////////////////////////////////////////////////////////
//The following MSpy functions to be used in the memory spy.

_ELASTOS Boolean MemSpyInitMemSpyArch()
{
    g_uCurrentAllocedTimesOfProcess = 0;

    memset(g_processHashList, NULL,
                    HASH_SIZE_OF_PROCESS * sizeof(PMEMSPYNODE));

    memset(g_threadHashList, NULL,
                    HASH_SIZE_OF_THREAD * sizeof(PMEMSPYTHREAD));

    return TRUE;
}

_ELASTOS Boolean MemSpyExitAndReportMemSpyInfo()
{
    if (MSpyHasMemoryLeak()) {
        BEGIN_MEMLEAK_DETECT_REPORT();

        UInt32 uTotalMemLeak = 0;

        PMEMSPYNODE pMemSpyNode = NULL;

        for (UInt32 i = 0; i < HASH_SIZE_OF_PROCESS; i++) {
            pMemSpyNode = g_processHashList[i];
            if (pMemSpyNode) {
                REPORT_ONE_MEMLEAK(pMemSpyNode->uAllocIndexInProcess, \
                                   pMemSpyNode->pvRequestAllocedBlock, \
                                   pMemSpyNode->uRequestAllocedSize);
                if (g_bPrintMore) {
                    MSpyOutputCallStack(pMemSpyNode);
                }

                if (false == pMemSpyNode->isAllocedbyVirtual &&
                   ISOVERRUN(pMemSpyNode->pvRequestAllocedBlock, \
                    pMemSpyNode->uRequestAllocedSize)
                    ) {
                    printf("\nAND, this heap block is overrun!\n");
                }

                uTotalMemLeak++;

                ForEachDLinkNode(PMEMSPYNODE, pMemSpyNode, \
                    g_processHashList[i]) {
                    REPORT_ONE_MEMLEAK(pMemSpyNode->uAllocIndexInProcess, \
                                        pMemSpyNode->pvRequestAllocedBlock, \
                                        pMemSpyNode->uRequestAllocedSize);
                    if (g_bPrintMore) {
                        MSpyOutputCallStack(pMemSpyNode);
                    }

                    if (false == pMemSpyNode->isAllocedbyVirtual &&
                    	ISOVERRUN(pMemSpyNode->pvRequestAllocedBlock, \
                        pMemSpyNode->uRequestAllocedSize)) {
                        printf("\nAND, this heap block is overrun!\n");
                    }

                    uTotalMemLeak++;
                }
            }
        }

        REPORT_TOTAL_MEMLEAKS(uTotalMemLeak);

        END_MEMLEAK_DETECT_REPORT();
    }

    MSpyEmptyThreadHashList();

    return TRUE;
}

UInt32 MSpyExpandRequestSize(const UInt32 ulRequestAllocSize)
{
    if ((UInt32)-1 - (UInt32)c_uMemSpyNodeSize - MEMSPYFOROVERRUN < \
        ulRequestAllocSize) {
        return (UInt32)-1;
    }
    return ulRequestAllocSize + (UInt32)c_uMemSpyNodeSize + MEMSPYFOROVERRUN;
}

PVoid MSpyRetrieveRequestHeapBlock(const PVoid pMSpyAllocHeapBlock)
{
    if (pMSpyAllocHeapBlock == NULL) return NULL;

    return (byte_t *)((UInt32)pMSpyAllocHeapBlock + (UInt32)c_uMemSpyNodeSize);
}

Void MSpyAddMemSpyNodeInfoToProcessHash(const PVoid pRequestedHeapBlock,
    const UInt32 uRequestAllocedSize)
{
    // Get the MEMSPYNODE node from pRequestedHeapBlock
    PMEMSPYNODE pMemSpyNode = \
            (PMEMSPYNODE)((byte_t *)pRequestedHeapBlock - c_uMemSpyNodeSize);

    assert(pMemSpyNode != NULL);

    ((DLinkNode *)pMemSpyNode)->Initialize();

    /////fill info into the node of MEMSPYNODE

    // fill field:uMagic
    pMemSpyNode->uMagic = MEMSPY_MAGIC;

    // fill field:uRequestAllocedSize
    pMemSpyNode->uRequestAllocedSize = uRequestAllocedSize;

    // fill field:pvRequestAllocedBlock
    pMemSpyNode->pvRequestAllocedBlock = pRequestedHeapBlock;

    // fill field:isAllocedbyVirtual
    pMemSpyNode->isAllocedbyVirtual = false;

    // fill field:uAllocIndexInProcess
    pMemSpyNode->uAllocIndexInProcess = ++g_uCurrentAllocedTimesOfProcess;

    // fill the fields about the current thread.(id and index)
    // Now, not used. 2004-3-23
//    MSpyGetThreadInfoOfMemSpyNode(pMemSpyNode);

    // Get stack information
    MSpyDumpCallStack(pMemSpyNode->addrCallStack);

    //add the node into the process hash list
    UInt32 uIndexOfProcessHash = HASHINDEXOFPROCESS(UInt32,
                    pRequestedHeapBlock);

    if (g_processHashList[uIndexOfProcessHash]) {
        g_processHashList[uIndexOfProcessHash]->InsertFirst(pMemSpyNode);
    }
    else {
        g_processHashList[uIndexOfProcessHash] = pMemSpyNode;
    }
}

Void MSpyGetThreadInfoOfMemSpyNode(PMEMSPYNODE pMemSpyNode)
{
    IThread *pCurrentThread = _CThread_GetCurrent();
    pCurrentThread->AddRef();

    if (pCurrentThread == NULL) return;

    // thread hash list index
    UInt32 uThreadHashIndex;
    uThreadHashIndex = HASHINDEXOFTHREAD(UInt32, pCurrentThread);

    PMEMSPYTHREAD pMemSpyThread = g_threadHashList[uThreadHashIndex];

    if (pMemSpyThread) {
        ForEachDLinkNode(PMEMSPYTHREAD, pMemSpyThread, \
            g_threadHashList[uThreadHashIndex]) {
            if (pMemSpyThread->uThreadID == (UInt32)pCurrentThread) {
                break;
            }
        }

        if (pMemSpyThread->uThreadID != (UInt32)pCurrentThread) {
            pMemSpyThread = MSpyNewMemSpyThreadNode((UInt32)pCurrentThread);
            g_threadHashList[uThreadHashIndex]->InsertFirst(pMemSpyThread);
        }
    }
    else {
        pMemSpyThread = MSpyNewMemSpyThreadNode((UInt32)pCurrentThread);
        g_threadHashList[uThreadHashIndex] = pMemSpyThread;
    }

    // Get MEMSPYNODE information about the current thread
    pMemSpyNode->nThreadID = (UInt32)pCurrentThread;

    pMemSpyNode->uAllocIndexInThread = \
                            ++pMemSpyThread->uCurrentAllocedTimesOfThread;
}

PMEMSPYTHREAD MSpyNewMemSpyThreadNode(const UInt32 nID)
{
    PMEMSPYTHREAD pMemSpyThreadNode = \
                    (PMEMSPYTHREAD)TaskMemAlloc(sizeof(MEMSPYTHREAD), FALSE);
    assert(pMemSpyThreadNode != NULL);

    pMemSpyThreadNode->uThreadID = nID;

    ((DLinkNode *)pMemSpyThreadNode)->Initialize();

    pMemSpyThreadNode->uCurrentAllocedTimesOfThread = 0;

    return pMemSpyThreadNode;
}

Void MSpyDumpCallStack(Address *pMemSpyNodeStack)
#ifdef _x86
{
#ifdef MSPY_DUMPCALLSTACK
    __asm__ __volatile__(
        "pushl      %%esi;"
        "pushl      %%edi;"
        "pushl      %%ecx;"
        "pushl      %%eax;"
        "movl       %%ebp, %%esi;"
        "movl       %0, %%edi;"
        "movl       %1, %%ecx;"
        "inc        %%ecx;"
        :
        :"g"(pMemSpyNodeStack), "g"(MEMSPY_STACK_INVALID_DEGREE)
    );

    //// ignore MEMSPY_STACK_INVALID_DEGREE calls
    __asm__ __volatile__(
    "Ignore:    or          %esi, %esi;"
                "jz         SetAllZero;"
                "movl       (%esi), %esi;"
                "loop       Ignore"
    );

    //// dump MEMSPY_STACK_RECORD_DEPTH call stack pointers
    __asm__ __volatile__(
            "movl       %0, %%ecx;"
    "Next:   or         %%esi, %%esi;"
            "jz         SetZero;"
            "movl       4(%%esi), %%eax;"
            "movl       (%%esi), %%esi;"
            "stosl;"
            "loop       Next;"
            "jmp        SetZero;"
    "SetAllZero:  mov   %0, %%ecx;"
             :
             :"g"(MEMSPY_STACK_RECORD_DEPTH)
    );

    //// dump 0 into the left fields of pMemSpyNodeStack
    __asm__ __volatile__(
    "SetZero:   xor        %eax, %eax;"
                "rep        stosl;"
                "popl       %eax;"
                "popl       %ecx;"
                "popl       %edi;"
                "popl       %esi"
    );
#endif //MSPY_DUMPCALLSTACK
}
#else // _x86
#ifdef _arm
{
#ifdef MSPY_DUMPCALLSTACK
    Address *fp;
    __asm__ (
        "mov %0, fp"
        :"=r"(fp)
    );

    for (Int32 i = 0; i < MEMSPY_STACK_RECORD_DEPTH; i++) {
        if (!fp) {
            pMemSpyNodeStack[i] = 0;
        }
        else {
            pMemSpyNodeStack[i] = *(fp - 1);
            fp = (Address *)*(fp-3);
        }
    }
#endif //MSPY_DUMPCALLSTACK
}
#endif // _arm
#endif // _x86

PVoid MSpyRetrieveExpandedHeapBlock(const PVoid pRequestHeapBlock)
{
    if (pRequestHeapBlock == NULL) return NULL;

    return (byte_t *)pRequestHeapBlock - c_uMemSpyNodeSize;
}

PMEMSPYNODE MSpySearchMemSpyNodeFromProcessHash(const PVoid pRequestHeapBlock)
{
    if (pRequestHeapBlock == NULL) return NULL;

    UInt32 uIndexOfProcessHash = HASHINDEXOFPROCESS(UInt32, pRequestHeapBlock);

    PMEMSPYNODE pMemSpyNode = g_processHashList[uIndexOfProcessHash];

    if (pMemSpyNode) {
        if (pMemSpyNode->pvRequestAllocedBlock == pRequestHeapBlock) {
            return pMemSpyNode;
        }

        ForEachDLinkNode(PMEMSPYNODE, pMemSpyNode, \
            g_processHashList[uIndexOfProcessHash]) {
            if (pMemSpyNode->pvRequestAllocedBlock == pRequestHeapBlock) {
                return pMemSpyNode;
            }
        }
    }

    return NULL;
}

Void MSpyDetachMemSpyNodeFromProcessHash(const PMEMSPYNODE pMemSpyNode)
{
    // assume that pMemSpyNode is in process hash list

    UInt32 uIndexOfProcessHash = HASHINDEXOFPROCESS(UInt32, \
                            pMemSpyNode->pvRequestAllocedBlock);

    // if node is header
    if (pMemSpyNode == g_processHashList[uIndexOfProcessHash]) {
        if ((PMEMSPYNODE)(pMemSpyNode->Next()) == pMemSpyNode) {
            g_processHashList[uIndexOfProcessHash] = NULL;
            return;
        }
        else {
            g_processHashList[uIndexOfProcessHash] = \
                                        (PMEMSPYNODE)(pMemSpyNode->Next());
            pMemSpyNode->Detach();
            return ;
        }
    }

    ((DLinkNode *)pMemSpyNode)->Detach();
}

_ELASTOS Boolean MSpyHasMemoryLeak()
{
    PMEMSPYNODE pMemSpyNode = NULL;

    for (UInt32 i = 0; i < HASH_SIZE_OF_PROCESS; i++) {
        pMemSpyNode = g_processHashList[i];
        if (pMemSpyNode) return TRUE;
    }

    return FALSE;
}

Void MSpyEmptyThreadHashList()
{
    PMEMSPYTHREAD pThreadNode = NULL;

    for (UInt32 i = 0; i < HASH_SIZE_OF_THREAD; i++) {
        pThreadNode = g_threadHashList[i];

        if (pThreadNode == NULL) continue;

        pThreadNode = (PMEMSPYTHREAD)(g_threadHashList[i]->Next());
        while (pThreadNode != g_threadHashList[i]) {
            pThreadNode->Detach();

            TaskMemFree(pThreadNode);

            pThreadNode = (PMEMSPYTHREAD)(g_threadHashList[i]->Next());
        } // end while

        TaskMemFree(pThreadNode);
    }// end for
}

Void MSpyOutputCallStack(const PMEMSPYNODE pMemSpyNode)
{
#ifdef MSPY_DUMPCALLSTACK
    if (pMemSpyNode == NULL) return;

    printf("CallStack:\n");

    for (UInt32 ui = 0; ui < MEMSPY_STACK_RECORD_DEPTH; ui++) {
        if (!pMemSpyNode->addrCallStack[ui]) continue;

        printf("%d : 0x%08x   ", ui, pMemSpyNode->addrCallStack[ui]);
    }

    printf("\n");
#endif //MSPY_DUMPCALLSTACK
}

Void MSpySetArgs(wchar_t uArgId, UInt32 uStopIndex, Address addr)
{
    if (uArgId == L'v') {
        g_bPrintMore = TRUE;
    }

    g_uStopIndex = uStopIndex;
    g_uOverrunAddress = addr;
}

ECode AddToProcessHash(PVoid  pVAddress, UInt32 size)
{

	UInt32 uExpandedSize = (UInt32)c_uMemSpyNodeSize;

	if ((UInt32)-1 == uExpandedSize) return E_OUT_OF_MEMORY;

	PVoid pExpandedHeapBlock;
	pExpandedHeapBlock = TaskMemAlloc(uExpandedSize, TRUE);
	if (NULL == pExpandedHeapBlock) return E_OUT_OF_MEMORY;

	void * pContext = _Elastos_CriticalSection_Enter(&g_sectMemSpy);

	PMEMSPYNODE pMemSpyNode = (PMEMSPYNODE)pExpandedHeapBlock;
	((DLinkNode *)pMemSpyNode)->Initialize();
	pMemSpyNode->uMagic = MEMSPY_MAGIC;
	pMemSpyNode->uRequestAllocedSize = size;
	pMemSpyNode->pvRequestAllocedBlock = pVAddress;
    pMemSpyNode->isAllocedbyVirtual = TRUE;
	pMemSpyNode->uAllocIndexInProcess = ++g_uCurrentAllocedTimesOfProcess;
	MSpyDumpCallStack(pMemSpyNode->addrCallStack);

	UInt32 uIndexOfProcessHash = HASHINDEXOFPROCESS(UInt32, pVAddress);

	if (g_processHashList[uIndexOfProcessHash]) {
		g_processHashList[uIndexOfProcessHash]->InsertFirst(pMemSpyNode);
	}
	else{
		g_processHashList[uIndexOfProcessHash] = pMemSpyNode;
	}
	_Elastos_CriticalSection_Leave(&g_sectMemSpy, pContext);

	if (g_uStopIndex && g_uCurrentAllocedTimesOfProcess == g_uStopIndex) {
    	if (g_uOverrunAddress != 0x0) {
        	ECode ec = SysSetBreakPoint(0, BreakPointType_ReadWrite, \
                            	(void *)((byte_t *)g_uOverrunAddress + size), \
                            	MEMSPYFOROVERRUN);
        	if (FAILED(ec)) {
            	printf("*ERROR* Failed to call SysSetBreakPoint \
                                (ec = %x)\n", ec);
            	DebugBreak();
            }
            return NOERROR;
        }

        printf("\n\n******************************************************\n");
        printf("\nStop at: index = 0x%x\n", g_uCurrentAllocedTimesOfProcess);
        printf("\nThe debugger gdb may offer what you want, start it up!\n");
        printf("\n******************************************************\n\n");

        DebugBreak();
	}

	return NOERROR;
}

Void RemoveFromProcessHash(PVoid pVAddress)
{
	if(NULL == pVAddress) return;

	PMEMSPYNODE pMemSpyNode = NULL;

	void * pContext = _Elastos_CriticalSection_Enter(&g_sectMemSpy);
	pMemSpyNode = MSpySearchMemSpyNodeFromProcessHash(pVAddress);

	if (NULL == pMemSpyNode) {
        printf("ERROR: free a non-spyed block. Freeing an invalid memory "
                "block, or freeing a valid block twice will cause \
                this error.\n");
        _Elastos_CriticalSection_Leave(&g_sectMemSpy, pContext);
        DebugBreak();
    }
	if (pMemSpyNode->uMagic != MEMSPY_MAGIC) {
        printf("ERROR: Freeing an invalid memory block, "
               "or freeing a valid block twice will cause this error.\n");
        DebugBreak();
    }

	MSpyDetachMemSpyNodeFromProcessHash(pMemSpyNode);

    _Elastos_CriticalSection_Leave(&g_sectMemSpy, pContext);

	TaskMemFree((void*)pMemSpyNode);
}

#endif //#if definded MEMORYSPY

